package testjava;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class CentralDirectoryHeader {
    // 0 4 Central directory file header signature = 0x02014b50
    //  4 2 Version made by
    //  6 2 Version needed to extract (minimum)
    //  8 2 General purpose bit flag
    // 10 2 Compression method
    // 12 2 File last modification time
    // 14 2 File last modification date
    // 16 4 CRC-32
    // 20 4 Compressed size
    // 24 4 Uncompressed size
    // 28 2 File name length (n)
    // 30 2 Extra field length (m)
    // 32 2 File comment length (k)
    // 34 2 Disk number where file starts
    // 36 2 Internal file attributes
    // 38 4 External file attributes
    // 42 4 Relative offset of local file header. This is the number of
    // bytes between the start of the first disk on which the file occurs,
    // and the start of the local file header. This allows software reading
    // the central directory to locate the position of the file inside the
    // .ZIP file.
    // 46 n File name
    // 46+n m Extra field
    // 46+n+m k File comment
    static final int SIG = 0x02014b50;
    static final int MINI_LEN = 46;

    short made;
    short mini;
    short flag;
    short method;
    int dtime;
    int crc32;
    int csize;
    int usize;
    short nameLength;
    short extraLength;
    short commentLength;
    short diskNO;
    short internal;
    int external;
    int offset;
    byte[] name;
    byte[] extra;

    public CentralDirectoryHeader(InputStream in) throws IOException {
        byte[] buffer = new byte[MINI_LEN];
        int len = in.read(buffer);
        if (len != buffer.length || SIG != Endian.getInt(buffer, 0)) {
            throw new IllegalArgumentException("UnReadable CentralDirectoryHeader");
        }
        made = Endian.getShort(buffer, 4);
        mini = Endian.getShort(buffer, 6);
        flag = Endian.getShort(buffer, 8);
        method = Endian.getShort(buffer, 10);
        dtime = Endian.getInt(buffer, 12);
        crc32 = Endian.getInt(buffer, 16);
        csize = Endian.getInt(buffer, 20);
        usize = Endian.getInt(buffer, 24);
        nameLength = Endian.getShort(buffer, 28);
        extraLength = Endian.getShort(buffer, 30);
        commentLength = Endian.getShort(buffer, 32);
        diskNO = Endian.getShort(buffer, 34);
        internal = Endian.getShort(buffer, 36);
        external = Endian.getInt(buffer, 38);
        offset = Endian.getInt(buffer, 42);
        name = new byte[nameLength];
        in.read(name);
        if (extraLength >= 0) {
            extra = new byte[extraLength];
            in.read(extra);
        }
        if (commentLength > 0) {
            in.skip(commentLength);
        }
    }

    public void writeTo(OutputStream out) throws IOException {
        out.write(Endian.getBytes(SIG));
        out.write(Endian.getBytes(made));
        out.write(Endian.getBytes(mini));
        out.write(Endian.getBytes(flag));
        out.write(Endian.getBytes(method));
        out.write(Endian.getBytes(dtime));
        out.write(Endian.getBytes(crc32));
        out.write(Endian.getBytes(csize));
        out.write(Endian.getBytes(usize));
        out.write(Endian.getBytes(nameLength));
        out.write(Endian.getBytes(extraLength));
        out.write(Endian.getBytes(commentLength));
        out.write(Endian.getBytes(diskNO));
        out.write(Endian.getBytes(internal));
        out.write(Endian.getBytes(external));
        out.write(Endian.getBytes(offset));
        out.write(name);
        if(null == extra)System.out.println(new String(name));
        out.write(extra);
        for (int i = 0; i < commentLength; i++) {
            out.write(0);
        }
    }

    @Override
    public String toString() {
        return "CentralDirectoryHeader [made=" + made + ", mini=" + mini + ", flag=" + flag + ", method=" + method + ", dtime=" + dtime
                + ", crc32=" + crc32 + ", csize=" + csize + ", usize=" + usize + ", nameLength=" + nameLength + ", extraLength=" + extraLength
                + ", commentLength=" + commentLength + ", diskNO=" + diskNO + ", internal=" + internal + ", external=" + external + ", offset="
                + offset + ", name=" + new String(name) + "]";
    }

    public int getSize() {
        return MINI_LEN + Endian.toUnsign(nameLength) + Endian.toUnsign(extraLength) + Endian.toUnsign(commentLength);
    }

}